/**
 * 建议使用 components/list.tsx
 * 基于nutui InfiniteLoading封装列表组件，但是web端兼容性有问题，官方BUG，小程序正常
 * 下拉列表组件
 *
 */
import {
  useState,
  useEffect,
  useRef,
  memo,
  forwardRef,
  useImperativeHandle,
} from "react";
import { View, Text } from "@tarojs/components";
import { Jd } from "@nutui/icons-react-taro";
import { InfiniteLoading, Loading } from "@nutui/nutui-react-taro";
import cn from "classnames";

interface Props {
  id?: string;
  api: any;
  Item: any;
  headerHeight?: any;
  layoutRef?: any;
  params?: any;
  className?: string;
  slotHeader?: any;
  itemProps?: any;
  itemClassGroup?: string;
  styles?: any;
  loadingSlot?: any;
  targetId?: string;
}

function List(
  {
    id,
    api,
    Item,
    layoutRef,
    params = {},
    className,
    slotHeader,
    itemProps = {},
    itemClassGroup = "",
    styles,
    loadingSlot,
    targetId = "infiniteLoadingId",
  }: Props,
  ref
) {
  const [dataSource, setDataSource] = useState([]);
  const [loading, setLoading] = useState(true);
  const [isLoaded, setLoaded] = useState(false);
  const [hasMore, setHasMore] = useState(true);
  const pageNo = useRef(1);
  const [pageSize] = useState(20);
  const _freshing = useRef(false);

  useImperativeHandle(ref, () => ({
    reload() {
      init();
    },
  }));

  useEffect(() => {
    init();
  }, []);

  /**
   * 获取数据
   * @param {}
   * @return
   */
  const getData = (reload, done?: () => void) => {
    if (reload) {
      setLoaded(false);
      pageNo.current = 1;
    } else {
      pageNo.current += 1;
    }
    return api({
      current: pageNo.current,
      pageSize,
      ...params,
    })
      .then((res) => {
        const { data }: any = res || {};
        const { total } = data || {};
        const list = data.list || [];
        done?.();
        if (reload) {
          setDataSource(list);
          if (total === list.length) {
            setHasMore(false);
          } else {
            setHasMore(true);
          }
        } else {
          const newData = dataSource.concat(list);
          setDataSource(newData);
          if (total === newData.length) {
            setHasMore(false);
          } else {
            setHasMore(true);
          }
        }
      })
      .catch((e) => {
        done?.();
        if (reload) {
          pageNo.current = 0;
        } else {
          pageNo.current -= 1;
        }
        layoutRef?.current?.setServiceError(true, e?.msg);
      })
      .finally(() => {
        loading && setLoading(false);
        setLoaded(true);
        setTimeout(() => {
          _freshing.current = false;
        }, 1000);
      });
  };

  const loadMore = (done: () => void) => {
    getData(false, done);
  };

  const refresh = (done: () => void) => {
    if (_freshing.current) return;
    _freshing.current = true;
    getData(true, done);
  };

  const init = () => {
    getData(true);
  };

  return loading ? (
    loadingSlot || (
      <View className="relative w-full flex-1 flex items-center justify-center">
        <Loading />
      </View>
    )
  ) : (
    <View
      className={cn(className, "relative w-full flex-1 flex")}
      style={styles}
    >
      <div id={targetId} className="absolute left-0 right-0 top-0 bottom-0">
        <InfiniteLoading
          pullingText={
            <View className="flex flex-col items-center h-[60Px] justify-center">
              <Jd />
              <Text className="text-[20rpx] mt-[4rpx]">松手刷新</Text>
            </View>
          }
          loadingText="加载中···"
          loadMoreText="没有啦～"
          pullRefresh
          target={targetId}
          threshold={60}
          hasMore={hasMore}
          onLoadMore={loadMore}
          onRefresh={refresh}
        >
          {dataSource && dataSource.length > 0 ? (
            <>
              {slotHeader}
              <View className={itemClassGroup}>
                {dataSource?.map((item: any) => (
                  <Item
                    key={item[id || "id"]}
                    data={item}
                    {...itemProps}
                    reload={() => getData(true)}
                  />
                ))}
              </View>
            </>
          ) : (
            isLoaded && (
              <View>
                {slotHeader}
                没有数据
              </View>
            )
          )}
        </InfiniteLoading>
      </div>
    </View>
  );
}

export default memo(forwardRef(List));
